#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
天翼云盘PC客户端
重构自原始脚本，提供登录、文件操作等功能
"""

import os
import re
import json
import logging
import hashlib
import uuid
import time
from typing import Dict, Optional, Any, List, Union, BinaryIO
import requests
from requests import Session
from datetime import datetime
import io

from ..base_client import (
    BaseCloudClient, LoginCredentials, PersistentLoginInfo, 
    AccountInfo, FileInfo, TrashItem
)
from .utils import (
    CryptoUtils, TimeUtils, StorageUtils, 
    SignatureUtils, TianyiUtils, TokenCacheUtils,
    PathCacheManager, FolderCacheManager
)
from .path_resolver import PathResolver

# 常量定义 - 严格按照原始脚本
ACCOUNT_TYPE = "02"
APP_ID = "8025431004"
CLIENT_TYPE = "10020"
VERSION = "6.2"

WEB_URL = "https://cloud.189.cn"
AUTH_URL = "https://open.e.189.cn"
API_URL = "https://api.cloud.189.cn"
# UPLOAD_URL = "https://api.cloud.189.cn"

RETURN_URL = "https://m.cloud.189.cn/zhuanti/2020/loginErrorPc/index.html"
CHANNEL_ID = "web_cloud.189.cn"

# 登录信息存储路径
# LOGIN_CACHE_DIR = "cache"
# LOGIN_CACHE_FILE = "tianyi_login_cache.json"


class TianyiPCClient(BaseCloudClient):
    """天翼云盘PC客户端 - 严格按照原始脚本实现"""
    
    def __init__(self, username: str = None, password: str = None, cache_token: Union[str, Dict[str, Any]] = None, cache_dir: str = None, enable_debug: bool = False, use_cache_first: bool = False, enable_path_cache: bool = False, path_cache_size: int = 10000, folder_cache_size: int = 1000, folder_cache_ttl: int = 300):
        """
        初始化天翼云盘客户端
        
        Args:
            username: 用户名（手机号或邮箱），如果use_cache_first=True且缓存存在，可以为None
            password: 密码，如果use_cache_first=True且缓存存在，可以为None
            cache_token: 缓存的token信息，支持以下格式：
                        - Dict[str, Any]: 直接传入token JSON对象
                        - str: token缓存文件路径
                        - None: 不使用预设token
            cache_dir: 缓存目录，默认为当前目录下的.cache（仅在cache_token为None时使用）
            enable_debug: 是否启用调试模式
            use_cache_first: 是否优先使用缓存登录
            enable_path_cache: 是否启用路径缓存，默认True
            path_cache_size: 路径缓存最大条目数，默认10000
            folder_cache_size: 文件夹缓存最大条目数，默认1000
            folder_cache_ttl: 文件夹缓存生存时间（秒），默认300秒
        """
        # 调用父类构造函数
        super().__init__(provider="tianyi")
        
        self.username = username
        self.password = password
        self.cache_token = cache_token
        self.cache_dir = cache_dir or os.path.join(os.getcwd(), '.cache')
        self.use_cache_first = use_cache_first
        
        # 初始化缓存管理器
        self.path_cache = PathCacheManager(max_size=path_cache_size, enable_cache=enable_path_cache)
        self.folder_cache = FolderCacheManager(max_size=folder_cache_size, enable_cache=enable_path_cache, ttl=folder_cache_ttl)
        
        # 确保缓存目录存在
        StorageUtils.ensure_dir(self.cache_dir)
        
        # 设置日志
        self.logger = self._setup_logger(enable_debug)
        
        # 初始化HTTP会话 - 按照原始脚本设置，增加网络优化
        self.session = Session()
        self.session.headers.update({
            'Accept': 'application/json;charset=UTF-8',
            'Referer': WEB_URL,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        })
        
        # 配置连接池和重试策略
        from requests.adapters import HTTPAdapter
        from urllib3.util.retry import Retry
        
        # 配置重试策略
        retry_strategy = Retry(
            total=3,  # 总重试次数
            backoff_factor=1,  # 重试间隔
            status_forcelist=[429, 500, 502, 503, 504],  # 需要重试的HTTP状态码
            allowed_methods=["HEAD", "GET", "POST"]  # 允许重试的HTTP方法
        )
        
        # 创建适配器
        adapter = HTTPAdapter(
            max_retries=retry_strategy,
            pool_connections=10,  # 连接池大小
            pool_maxsize=20  # 最大连接数
        )
        
        # 挂载适配器
        self.session.mount("http://", adapter)
        self.session.mount("https://", adapter)
        
        # 设置默认超时时间
        self.session.timeout = 30
        
        # 登录状态相关 - 按照原始脚本结构
        self.login_param = None
        # self.family_id = None  # 未使用的变量
        self.identity = None
        self.token_info = None
        self._last_login_check = 0  # 上次登录检查时间戳
        self._login_check_interval = 300  # 登录检查间隔（5分钟）
        
        # 如果启用缓存优先，尝试从缓存加载token
        if self.use_cache_first:
            self._try_load_from_cache()
        
        # 初始化路径解析器
        self.path_resolver = PathResolver(self)
        
        self.logger.info(f"天翼云盘客户端初始化完成，用户名: {username}, 缓存优先: {use_cache_first}, 路径缓存: {enable_path_cache}")
        if enable_path_cache:
            self.logger.info(f"缓存配置 - 路径缓存: {path_cache_size}条, 文件夹缓存: {folder_cache_size}条, TTL: {folder_cache_ttl}秒")
    
    def _normalize_path(self, path: str) -> str:
        """
        标准化路径 - 适配天翼云盘的扁平化存储机制
        
        Args:
            path: 原始路径
            
        Returns:
            str: 标准化后的路径
        """
        if not path or path == "/":
            return ""
        
        # 统一使用正斜杠，去掉首尾空格
        normalized = path.replace('\\', '/').strip()
        
        # 确保路径以 / 开头（天翼云盘的存储格式）
        if not normalized.startswith('/'):
            normalized = '/' + normalized
        
        # 去掉末尾的斜杠（除非是根目录）
        if normalized != '/' and normalized.endswith('/'):
            normalized = normalized.rstrip('/')
        
        return normalized

    def _extract_parent_path_and_name(self, full_path: str) -> tuple:
        """
        从完整路径中提取父路径和文件/文件夹名
        适配天翼云盘的扁平化存储机制
        
        Args:
            full_path: 完整路径
            
        Returns:
            tuple: (父路径, 文件/文件夹名)
        """
        normalized_path = self._normalize_path(full_path)
        
        if not normalized_path or normalized_path == "/":
            return "", ""
        
        # 对于天翼云盘，我们需要特殊处理
        # 如果是单层路径（如 /文件夹），父路径为空，名称为 "文件夹"
        # 如果是多层路径（如 /文件夹/子文件夹），父路径为 "/文件夹"，名称为 "子文件夹"
        
        parts = normalized_path.strip('/').split('/')
        if len(parts) == 1:
            # 单层路径，直接在根目录
            return "", parts[0]
        else:
            # 多层路径，父路径是除最后一部分外的所有部分
            parent_parts = parts[:-1]
            parent_path = '/' + '/'.join(parent_parts)
            name = parts[-1]
            return parent_path, name

    def _invalidate_path_cache(self, path_prefix: str = None) -> int:
        """
        清理路径缓存
        
        Args:
            path_prefix: 路径前缀，如果提供则只清理匹配的路径，否则清理所有
            
        Returns:
            int: 清理的缓存条目数
        """
        if path_prefix:
            return self.path_cache.invalidate_prefix(path_prefix)
        else:
            self.path_cache.clear()
            return 0

    def _refresh_cache_for_path(self, path: str) -> bool:
        """
        刷新指定路径的缓存
        
        Args:
            path: 要刷新的路径
            
        Returns:
            bool: 刷新是否成功
        """
        try:
            # 从缓存中移除
            self.path_cache.remove(path)
            
            # 重新获取文件信息（这会自动更新缓存）
            file_info = self.get_file_info(path)
            return file_info is not None
        except Exception as e:
            self.logger.error(f"刷新路径缓存失败: {path}, 错误: {e}")
            return False

    def _folder_exists_no_cache(self, remote_path: str) -> bool:
        """
        检查文件夹是否存在 - 非缓存方式，直接通过API查询
        
        Args:
            remote_path: 远程文件夹路径
            
        Returns:
            bool: 文件夹是否存在
        """
        try:
            # 标准化路径
            normalized_path = self._normalize_path(remote_path)
            
            if not normalized_path:
                return True  # 根目录总是存在
            
            # 提取父路径和文件夹名
            parent_path, folder_name = self._extract_parent_path_and_name(normalized_path)
            
            # 获取父目录ID（不使用缓存）
            if not parent_path:
                parent_id = "-11"  # 根目录
            else:
                # 递归检查父路径
                if not self._folder_exists_no_cache(parent_path):
                    return False
                parent_id = self._find_folder_id_by_path_no_cache(parent_path)
                if not parent_id:
                    return False
            
            # 直接查询父目录中的文件列表
            files = self.get_files(parent_id)
            if files:
                for file in files:
                    if file.get('name') == folder_name and file.get('isFolder', False):
                        self.logger.debug(f"非缓存检查：文件夹存在 {normalized_path}")
                        return True
            
            self.logger.debug(f"非缓存检查：文件夹不存在 {normalized_path}")
            return False
            
        except Exception as e:
            self.logger.error(f"非缓存文件夹存在检查异常: {e}")
            return False

    def _find_folder_id_by_path_no_cache(self, path: str) -> Optional[str]:
        """
        根据路径查找文件夹ID - 非缓存方式，直接通过API查询
        
        Args:
            path: 文件夹路径
            
        Returns:
            Optional[str]: 文件夹ID，找不到返回None
        """
        if path == "/" or path == "":
            return "-11"
        
        # 标准化路径
        normalized_path = self._normalize_path(path)
        if not normalized_path:
            return "-11"
        
        # 处理多层路径，逐层查找
        path_parts = normalized_path.strip('/').split('/')
        current_folder_id = "-11"  # 从根目录开始
        
        for part in path_parts:
            # 在当前文件夹中查找下一级文件夹
            folder_found = False
            files = self.get_files(current_folder_id)
            if files:
                for file in files:
                    file_name = file.get('name', '')
                    is_folder = file.get('isFolder', False)
                    file_id = file.get('id', '')
                    
                    if file_name == part and is_folder:
                        current_folder_id = file_id
                        folder_found = True
                        self.logger.debug(f"非缓存查找：找到文件夹 {part} -> {file_id}")
                        break
            
            if not folder_found:
                self.logger.debug(f"非缓存查找：找不到文件夹 {part}")
                return None
        
        return current_folder_id
        
    def _try_load_from_cache(self) -> bool:
        """
        尝试从缓存加载token
        优先级：JSON对象 > 文件地址 > 用户名缓存目录
        """
        try:
            # 优先级1：直接传入的JSON对象
            if isinstance(self.cache_token, dict):
                self.token_info = self.cache_token
                self.logger.info("从传入的JSON对象加载token成功")
                
                # 验证token是否仍然有效
                if self.is_login():
                    self.logger.info("传入的token仍然有效")
                    return True
                else:
                    self.logger.warning("传入的token已失效，需要重新登录")
                    self.token_info = None
            
            # 优先级2：传入的文件路径
            elif isinstance(self.cache_token, str) and os.path.exists(self.cache_token):
                try:
                    with open(self.cache_token, 'r', encoding='utf-8') as f:
                        cached_token = json.load(f)
                    
                    if cached_token:
                        self.token_info = cached_token
                        self.logger.info(f"从指定文件加载token成功: {self.cache_token}")
                        
                        # 验证token是否仍然有效
                        if self.is_login():
                            self.logger.info("文件中的token仍然有效")
                            return True
                        else:
                            self.logger.warning("文件中的token已失效，需要重新登录")
                            self.token_info = None
                except Exception as e:
                    self.logger.error(f"从指定文件加载token失败: {e}")
            
            # 优先级3：使用用户名从缓存目录加载（原有逻辑）
            elif self.username:
                cached_token = TokenCacheUtils.load_token(self.username, self.cache_dir)
                if cached_token:
                    self.token_info = cached_token
                    self.logger.info(f"从缓存目录加载token成功: {self.username}")
                    
                    # 验证token是否仍然有效
                    if self.is_login():
                        self.logger.info("缓存目录中的token仍然有效")
                        return True
                    else:
                        self.logger.warning("缓存目录中的token已失效，需要重新登录")
                        self.token_info = None
                else:
                    self.logger.info("未找到有效的token缓存")
            else:
                self.logger.info("未提供token缓存信息")
                
        except Exception as e:
            self.logger.error(f"从缓存加载token失败: {e}")
        
        return False
        
    def _setup_logger(self, enable_debug: bool) -> logging.Logger:
        """设置日志记录器"""
        logger = logging.getLogger(f"TianyiPCClient_{self.username}")
        logger.setLevel(logging.DEBUG if enable_debug else logging.INFO)
        
        # 避免重复添加handler
        if not logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
            )
            handler.setFormatter(formatter)
            logger.addHandler(handler)
        
        return logger
    
    def _make_request_with_retry(self, method: str, url: str, max_retries: int = 3, **kwargs) -> Optional[requests.Response]:
        """
        带重试机制的HTTP请求方法
        
        Args:
            method: HTTP方法 (GET, POST等)
            url: 请求URL
            max_retries: 最大重试次数
            **kwargs: 其他请求参数
            
        Returns:
            Optional[requests.Response]: 响应对象，失败返回None
        """
        for attempt in range(max_retries):
            try:
                # 设置默认超时时间
                if 'timeout' not in kwargs:
                    kwargs['timeout'] = 15
                
                response = self.session.request(method, url, **kwargs)
                
                # 检查响应状态
                if response.status_code == 200:
                    return response
                elif response.status_code in [429, 500, 502, 503, 504]:
                    # 服务器错误，可以重试
                    self.logger.warning(f"HTTP {response.status_code} 错误，尝试重试 ({attempt + 1}/{max_retries})")
                    if attempt < max_retries - 1:
                        time.sleep(2 ** attempt)  # 指数退避
                        continue
                else:
                    # 客户端错误，不重试
                    self.logger.error(f"HTTP {response.status_code} 错误，不重试")
                    return response
                    
            except Exception as e:
                self.logger.warning(f"请求失败 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)  # 指数退避
                    continue
                else:
                    self.logger.error(f"请求最终失败: {e}")
        
        return None

    def timestamp(self) -> int:
        """获取时间戳 - 按照原始脚本"""
        return TimeUtils.get_timestamp()
    
    def client_suffix(self) -> Dict[str, str]:
        """客户端后缀参数 - 按照原始脚本"""
        import random
        rand_num = random.randint(10000, 99999)
        rand_num2 = random.randint(1000000000, 9999999999)
        return {
            "clientType": "TELEPC",
            "version": VERSION,
            "channelId": CHANNEL_ID,
            "rand": f"{rand_num}_{rand_num2}"
        }
    
    def signature_header(self, url: str, method: str, params: str = "", is_family: bool = False) -> Dict[str, str]:
        """生成签名头 - 按照原始脚本"""
        if not self.token_info:
            return {}
        
        date_of_gmt = TimeUtils.get_http_date_str()
        session_key = self.token_info.get('sessionKey', '')
        session_secret = self.token_info.get('sessionSecret', '')
        
        if is_family:
            session_key = self.token_info.get('familySessionKey', '')
            session_secret = self.token_info.get('familySessionSecret', '')
        
        # 生成HMAC签名 - 严格按照Go实现
        url_path = re.search(r'://[^/]+((/[^/\s?#]+)*)', url).group(1)
        data = f"SessionKey={session_key}&Operate={method}&RequestURI={url_path}&Date={date_of_gmt}"
        if params:
            data += f"&params={params}"
        
        signature = SignatureUtils.hmac_sha1(session_secret, data).upper()
        
        return {
            "Date": date_of_gmt,
            "SessionKey": session_key,
            "X-Request-ID": str(uuid.uuid4()),
            "Signature": signature
        }
    
    def get_encrypt_conf(self) -> Optional[Dict[str, Any]]:
        """获取加密配置 - 严格按照原始脚本"""
        url = f"{AUTH_URL}/api/logbox/config/encryptConf.do"
        data = {'appId': APP_ID}
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
        
        try:
            response = self.session.post(url, data=data, headers=headers)
            if response.status_code == 200:
                return response.json()
        except Exception as e:
            self.logger.error(f"获取加密配置失败: {e}")
        return None
    
    def get_login_param(self) -> bool:
        """获取登录参数 - 严格按照原始脚本"""
        # 清除cookie
        self.session.cookies.clear()
        
        # 获取登录页面参数
        login_url = f"{WEB_URL}/api/portal/unifyLoginForPC.action"
        params = {
            'appId': APP_ID,
            'clientType': CLIENT_TYPE,
            'returnURL': RETURN_URL,
            'timeStamp': str(self.timestamp())
        }
        
        try:
            response = self.session.get(login_url, params=params)
            if response.status_code == 200:
                content = response.text
                # 使用正则表达式提取参数 - 按照原始脚本
                captcha_token_match = re.search(r"'captchaToken' value='(.+?)'", content)
                lt_match = re.search(r'lt = "(.+?)"', content)
                param_id_match = re.search(r'paramId = "(.+?)"', content)
                req_id_match = re.search(r'reqId = "(.+?)"', content)
                
                if not all([captcha_token_match, lt_match, param_id_match, req_id_match]):
                    self.logger.error("解析登录页面参数失败")
                    return False
                
                # 获取加密配置
                encrypt_conf = self.get_encrypt_conf()
                if not encrypt_conf or encrypt_conf.get('result') != 0:
                    self.logger.error("获取加密配置失败")
                    return False
                
                pub_key = encrypt_conf['data']['pubKey']
                pre = encrypt_conf['data']['pre']
                
                # 构建完整的RSA公钥 - 按照原始脚本
                rsa_key = f"-----BEGIN PUBLIC KEY-----\n{pub_key}\n-----END PUBLIC KEY-----"
                
                self.login_param = {
                    'captchaToken': captcha_token_match.group(1),
                    'lt': lt_match.group(1),
                    'paramId': param_id_match.group(1),
                    'reqId': req_id_match.group(1),
                    'jRsaKey': rsa_key,
                    'pre': pre
                }
                return True
        except Exception as e:
            self.logger.error(f"获取登录参数失败: {e}")
        return False
    
    def login_internal(self) -> bool:
        """登录天翼云盘 - 严格按照原始脚本流程，支持缓存优先"""
        print(f"[DEBUG] 开始登录天翼云盘，用户名: {self.username}")
        
        # 如果已经从缓存加载了有效token，直接返回成功
        if self.is_login():
            print(f"[DEBUG] 已登录（从缓存或之前登录），无需重复登录")
            self.logger.info("已登录，无需重复登录")
            return True
        
        # 如果没有用户名或密码，且缓存加载失败，则无法登录
        if not self.username or not self.password:
            print(f"[DEBUG] 用户名或密码为空，且缓存登录失败，无法进行登录")
            self.logger.error("用户名或密码为空，且缓存登录失败，无法进行登录")
            return False
        
        # 检查密码是否为None
        if self.password is None:
            print(f"[DEBUG] 密码为None，无法进行登录")
            self.logger.error("密码为None，无法进行登录")
            return False
        
        # 生成身份标识 - 按照原始脚本
        new_identity = hashlib.md5((self.username + self.password).encode()).hexdigest()
        
        # 如果已登录且身份相同，直接返回
        if self.is_login() and self.identity == new_identity:
            print(f"[DEBUG] 已登录，无需重复登录")
            self.logger.info("已登录，无需重复登录")
            return True
        
        # 获取登录参数
        print(f"[DEBUG] 开始获取登录参数...")
        if not self.get_login_param():
            print(f"[DEBUG] 获取登录参数失败")
            return False
        
        print(f"[DEBUG] 登录参数获取成功，开始RSA加密...")
        # RSA加密用户名和密码 - 严格按照原始脚本
        rsa_username = CryptoUtils.rsa_encrypt(self.login_param['jRsaKey'], self.username)
        rsa_password = CryptoUtils.rsa_encrypt(self.login_param['jRsaKey'], self.password)
        
        if not rsa_username or not rsa_password:
            print(f"[DEBUG] 加密用户名密码失败")
            self.logger.error("加密用户名密码失败")
            return False
        
        # 添加前缀 - 按照原始脚本
        pre = self.login_param['pre']
        rsa_username = pre + rsa_username
        rsa_password = pre + rsa_password
        
        # 登录请求 - 按照原始脚本
        login_url = f"{AUTH_URL}/api/logbox/oauth2/loginSubmit.do"
        login_data = {
            'appKey': APP_ID,
            'accountType': ACCOUNT_TYPE,
            'userName': rsa_username,
            'password': rsa_password,
            'validateCode': '',
            'captchaToken': self.login_param.get('captchaToken', ''),
            'returnUrl': RETURN_URL,
            'dynamicCheck': 'FALSE',
            'clientType': CLIENT_TYPE,
            'cb_SaveName': '1',
            'isOauth2': 'false',
            'state': '',
            'paramId': self.login_param['paramId']
        }
        
        headers = {
            'REQID': self.login_param['reqId'],
            'lt': self.login_param['lt']
        }
        
        try:
            print(f"[DEBUG] 发送登录请求到: {login_url}")
            response = self.session.post(login_url, data=login_data, headers=headers)
            print(f"[DEBUG] 登录请求响应状态码: {response.status_code}")
            if response.status_code == 200:
                result = response.json()
                print(f"[DEBUG] 登录响应结果: {result}")
                if result.get('result') == 0:
                    # 登录成功，获取重定向URL - 按照原始脚本
                    to_url = result.get('toUrl')
                    if to_url:
                        print(f"[DEBUG] 获取到重定向URL: {to_url}")
                        # 访问重定向URL获取session
                        redirect_response = self.session.get(to_url)
                        if redirect_response.status_code == 200:
                            print(f"[DEBUG] 重定向成功，开始获取session")
                            # 获取session - 按照原始脚本
                            session_url = f"{API_URL}/getSessionForPC.action"
                            session_params = self.client_suffix()
                            session_params['redirectURL'] = to_url
                            
                            session_response = self.session.post(session_url, params=session_params)
                            if session_response.status_code == 200:
                                session_result = session_response.json()
                                print(f"[DEBUG] Session响应: {session_result}")
                                if session_result.get('res_code') == 0 or session_result.get('resCode') == 0:
                                    # 保存token信息 - 按照原始脚本
                                    self.token_info = session_result
                                    self.identity = new_identity
                                    print(f"[DEBUG] Token信息: {self.token_info}")
                                    
                                    # 保存token到缓存
                                    if self.use_cache_first:
                                        TokenCacheUtils.save_token(self.username, self.token_info, self.cache_dir)
                                        self.logger.info("Token已保存到缓存")
                                    
                                    self.logger.info(f"登录成功: {self.token_info.get('loginName', self.username)}")
                                    return True
                                else:
                                    res_message = session_result.get('resMessage') or session_result.get('res_message')
                                    self.logger.error(f"获取session失败: {res_message}")
                else:
                    self.logger.error(f"登录失败: {result.get('msg', '未知错误')}")
        except Exception as e:
            self.logger.error(f"登录请求失败: {e}")
        
        return False
    
    def is_login(self) -> bool:
        """检查是否已登录 - 按照原始脚本，增加容错机制和缓存优化"""
        if self.token_info is None:
            return False
        
        # 首先检查token是否存在基本信息
        if not self.token_info.get('accessToken') or not self.token_info.get('sessionKey'):
            return False
        
        # 检查是否需要进行网络验证（避免频繁检查）
        current_time = time.time()
        if current_time - self._last_login_check < self._login_check_interval:
            # 在检查间隔内，假设登录仍有效
            return True
        
        # 通过调用getUserInfo接口验证登录状态，增加重试机制
        max_retries = 2
        for attempt in range(max_retries):
            try:
                url = f"{API_URL}/getUserInfo.action"
                params = self.client_suffix()
                headers = self.signature_header(url, "GET")
                
                # 设置较短的超时时间
                response = self.session.get(url, params=params, headers=headers, timeout=10)
                
                if response.status_code == 200:
                    result = response.json()
                    is_valid = result.get('res_code') == 0 or result.get('resCode') == 0
                    if is_valid:
                        self._last_login_check = current_time  # 更新检查时间
                        return True
                    else:
                        self.logger.warning(f"登录状态检查返回错误: {result.get('res_message', result.get('resMessage', '未知错误'))}")
                        return False
                else:
                    self.logger.warning(f"登录状态检查HTTP错误: {response.status_code}")
                    
            except Exception as e:
                self.logger.warning(f"登录状态检查失败 (尝试 {attempt + 1}/{max_retries}): {e}")
                if attempt < max_retries - 1:
                    time.sleep(1)  # 重试前等待1秒
                    continue
        
        # 如果网络检查失败，但token信息完整，假设仍然有效
        # 这是一种容错机制，避免因网络问题导致的误判
        if self.token_info.get('accessToken') and self.token_info.get('sessionKey'):
            self.logger.info("网络检查失败，但token信息完整，假设登录仍有效")
            self._last_login_check = current_time  # 更新检查时间，避免频繁重试
            return True
            
        return False
    
    def get_user_info(self) -> Optional[Dict[str, Any]]:
        """获取用户信息"""
        if not self.token_info:
            return None
            
        try:
            url = f"{API_URL}/getUserInfo.action"
            params = self.client_suffix()
            headers = self.signature_header(url, "GET")
            
            response = self.session.get(url, params=params, headers=headers)
            
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    return result
                else:
                    self.logger.error(f"获取用户信息失败: {result.get('res_message', '未知错误')}")
        except Exception as e:
            self.logger.error(f"获取用户信息异常: {e}")
        
        return None

    # def get_cached_token(self) -> Optional[Dict[str, Any]]:
    #     """
    #     获取当前缓存的token信息
    #     
    #     Returns:
    #         Optional[Dict[str, Any]]: 当前的token信息，如果未登录则返回None
    #     """
    #     return self.token_info.copy() if self.token_info else None

    def check_login_status(self) -> bool:
        """检查登录状态"""
        return self.is_login()
    
    def logout(self) -> bool:
        """登出并清理缓存"""
        try:
            # 清理令牌信息
            self.token_info = None
            self.login_param = None
            self.identity = None
            self.is_authenticated = False  # 重置认证状态
            
            # 清理session cookies
            self.session.cookies.clear()
            
            self.logger.info("登出成功")
            return True
        except Exception as e:
            self.logger.error(f"登出失败: {e}")
            return False
    
    # 文件操作方法 - 按照原始脚本实现
    def get_files(self, folder_id: str = "-11", page_num: int = 1, page_size: int = 1000) -> Optional[List[Dict[str, Any]]]:
        """
        获取文件列表 - 严格按照原始脚本实现，集成缓存功能
        
        Args:
            folder_id: 文件夹ID，默认"-11"表示根目录
            page_num: 页码，从1开始
            page_size: 每页大小
        
        Returns:
            List[Dict[str, Any]]: 文件列表，包含文件和文件夹
        """
        if not self.is_login():
            self.logger.error("未登录，无法获取文件列表")
            return None
        
        if folder_id is None:
            folder_id = "-11"  # 根目录
        
        # 尝试从缓存获取
        cached_files = self.folder_cache.get(folder_id)
        if cached_files is not None:
            self.logger.debug(f"从缓存获取文件夹 {folder_id} 的文件列表，共 {len(cached_files)} 项")
            return cached_files
        
        # 按照原始脚本的API调用方式
        url = f"{API_URL}/listFiles.action"
        params = {
            'folderId': folder_id,
            'pageNum': page_num,
            'pageSize': page_size,
            'mediaType': 0,
            'iconOption': 5,
            'orderBy': 'lastOpTime',
            'descending': 'true'
        }
        params.update(self.client_suffix())
        
        headers = self.signature_header(url, "GET")
        
        try:
            response = self.session.get(url, params=params, headers=headers)
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    # 按照原始脚本的数据结构处理
                    file_list_ao = result.get('fileListAO', {})
                    files = file_list_ao.get('fileList', [])
                    folders = file_list_ao.get('folderList', [])
                    
                    # 合并文件和文件夹列表，按照原始脚本的方式
                    all_items = []
                    
                    # 添加文件夹
                    for folder in folders:
                        folder['isFolder'] = True
                        all_items.append(folder)
                    
                    # 添加文件
                    for file in files:
                        file['isFolder'] = False
                        # 调试：打印文件数据结构
                        self.logger.debug(f"文件数据结构: {file}")
                        all_items.append(file)
                    
                    # 将结果放入缓存
                    self.folder_cache.put(folder_id, all_items)
                    
                    self.logger.info(f"获取文件列表成功，文件夹: {len(folders)}个，文件: {len(files)}个")
                    return all_items
                else:
                    error_msg = result.get('res_message') or result.get('resMessage', '未知错误')
                    self.logger.error(f"获取文件列表失败: {error_msg}")
            else:
                self.logger.error(f"获取文件列表请求失败，状态码: {response.status_code}")
        except Exception as e:
            self.logger.error(f"获取文件列表异常: {e}")
        
        return None
    
    def _get_files_no_cache(self, folder_id: str = "-11", page_num: int = 1, page_size: int = 1000) -> Optional[List[Dict[str, Any]]]:
        """
        获取文件列表 - 不使用缓存，直接从API获取最新数据
        用于诊断和验证目的
        
        Args:
            folder_id: 文件夹ID，默认"-11"表示根目录
            page_num: 页码，从1开始
            page_size: 每页大小
        
        Returns:
            List[Dict[str, Any]]: 文件列表，包含文件和文件夹
        """
        if not self.is_login():
            self.logger.error("未登录，无法获取文件列表")
            return None
        
        if folder_id is None:
            folder_id = "-11"  # 根目录
        
        # 直接调用API，不检查缓存
        url = f"{API_URL}/listFiles.action"
        params = {
            'folderId': folder_id,
            'pageNum': page_num,
            'pageSize': page_size,
            'mediaType': 0,
            'iconOption': 5,
            'orderBy': 'lastOpTime',
            'descending': 'true'
        }
        params.update(self.client_suffix())
        
        headers = self.signature_header(url, "GET")
        
        try:
            response = self.session.get(url, params=params, headers=headers)
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    # 按照原始脚本的数据结构处理
                    file_list_ao = result.get('fileListAO', {})
                    files = file_list_ao.get('fileList', [])
                    folders = file_list_ao.get('folderList', [])
                    
                    # 合并文件和文件夹列表，按照原始脚本的方式
                    all_items = []
                    
                    # 添加文件夹
                    for folder in folders:
                        folder['isFolder'] = True
                        all_items.append(folder)
                    
                    # 添加文件
                    for file in files:
                        file['isFolder'] = False
                        all_items.append(file)
                    
                    # 注意：这里不放入缓存，直接返回
                    self.logger.debug(f"直接从API获取文件列表成功，文件夹: {len(folders)}个，文件: {len(files)}个")
                    return all_items
                else:
                    error_msg = result.get('res_message') or result.get('resMessage', '未知错误')
                    self.logger.error(f"获取文件列表失败: {error_msg}")
            else:
                self.logger.error(f"获取文件列表请求失败，状态码: {response.status_code}")
        except Exception as e:
            self.logger.error(f"获取文件列表异常: {e}")
        
        return None
    
    def create_folder(self, remote_path: str) -> bool:
        """
        创建文件夹 - BaseCloudClient接口实现
        
        Args:
            remote_path: 远程文件夹路径
            
        Returns:
            bool: 创建是否成功
        """
        return self.create_folder_standard(remote_path)
    
    def create_folder_internal(self, folder_name: str, parent_id: str = "-11") -> Optional[Dict[str, Any]]:
        """
        创建文件夹 - 集成缓存失效功能
        
        Args:
            folder_name: 文件夹名称
            parent_id: 父文件夹ID，默认为根目录(-11)
            
        Returns:
            Optional[Dict[str, Any]]: 创建成功返回文件夹信息字典，失败返回None
        """
        if not self.check_login_status():
            if not self.login():
                return None
        
        if parent_id is None:
            parent_id = "-11"  # 根目录
        
        url = "https://api.cloud.189.cn/createFolder.action"
        params = {
            'parentFolderId': parent_id,  # 修正参数名
            'folderName': folder_name
        }
        params.update(self.client_suffix())
        
        headers = self.signature_header(url, "POST")
        
        try:
            response = self.session.post(url, data=params, headers=headers)
            print(f"[DEBUG] 创建文件夹请求参数: {params}")
            print(f"[DEBUG] 创建文件夹请求头: {headers}")
            print(f"[DEBUG] 创建文件夹响应状态码: {response.status_code}")
            print(f"[DEBUG] 创建文件夹响应内容: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                print(f"[DEBUG] 创建文件夹解析结果: {result}")
                
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    folder_id = result.get('id')
                    self.logger.info(f"文件夹创建成功: {folder_name} (ID: {folder_id})")
                    
                    # 使父文件夹缓存失效
                    self.folder_cache.remove(parent_id)
                    
                    # 返回完整的文件夹信息字典
                    folder_info = {
                        'fileId': folder_id,
                        'fileName': folder_name,
                        'createTime': result.get('createTime', ''),
                        'isFolder': True,
                        'parentId': parent_id
                    }
                    return folder_info
                else:
                    self.logger.error(f"创建文件夹失败: {result.get('res_message', result.get('resMessage'))}")
                    return None
        except Exception as e:
            self.logger.error(f"创建文件夹请求失败: {e}")
        
        return None
    
    def upload_file_internal(self, file_data: Union[str, bytes, BinaryIO], filename: str, 
                   parent_id: str = None, overwrite: bool = True, 
                   try_fast_upload: bool = True) -> Optional[Dict[str, Any]]:
        """上传文件
        
        Args:
            file_data: 文件数据（文件路径、字节数据或文件对象）
            filename: 文件名
            parent_id: 父文件夹ID，None表示根目录
            overwrite: 是否覆盖同名文件
            try_fast_upload: 是否尝试秒传
        
        Returns:
            Dict[str, Any]: 上传成功返回文件信息，失败返回None
        """
        if not self.check_login_status():
            if not self.login():
                return None
        
        if parent_id is None:
            parent_id = "-11"  # 根目录
        
        # 获取文件大小和MD5
        file_size = CryptoUtils.get_file_size(file_data)
        file_md5 = CryptoUtils.calculate_file_md5(file_data)
        
        self.logger.info(f"开始上传文件: {filename} (大小: {file_size} 字节, MD5: {file_md5})")
        
        # 尝试秒传
        if try_fast_upload:
            self.logger.info("尝试秒传...")
            fast_result = self._fast_upload(filename, file_size, file_md5, parent_id)
            if fast_result:
                return fast_result
            self.logger.info("秒传失败，开始普通上传")
        
        # 普通上传
        return self._upload_file_stream(file_data, filename, file_size, file_md5, parent_id, overwrite)

    def check_quick_upload(self, file_path: str, file_md5: str, file_size: int) -> bool:
        """
        检查是否可以秒传 - 实现check_quick_upload方法
        
        Args:
            file_path: 文件路径
            file_md5: 文件MD5值
            file_size: 文件大小
            
        Returns:
            bool: 是否可以秒传
        """
        try:
            self.logger.debug(f"检查秒传: {file_path}, MD5: {file_md5}, 大小: {file_size}")
            
            # 使用现有的秒传逻辑
            url = f"{API_URL}/createFileByFile.action"
            
            form_data = {
                'parentFolderId': self._find_folder_id_by_path_cached(os.path.dirname(file_path)),
                'fileName': os.path.basename(file_path),
                'fileSize': str(file_size),
                'md5': file_md5,
                'lastWrite': str(int(time.time() * 1000)),
                'flag': '1',
                'resumePolicy': '1',
                'isLog': '0'
            }
            
            headers = self.signature_header(url, "POST")
            
            response = self.session.post(url, data=form_data, headers=headers, timeout=30)
            
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    self.logger.info(f"秒传检查成功: {file_path}")
                    return True
                else:
                    error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                    self.logger.debug(f"秒传检查失败: {error_msg}")
                    return False
            else:
                self.logger.debug(f"秒传检查请求失败，状态码: {response.status_code}")
                return False
                
        except Exception as e:
            self.logger.error(f"秒传检查异常: {e}")
            return False

    def _fast_upload(self, filename: str, file_size: int, file_md5: str, parent_id: str) -> Optional[Dict[str, Any]]:
        """
        执行秒传 - 参考Go语言版本的RapidUpload实现
        
        Args:
            filename: 文件名
            file_size: 文件大小（字节）
            file_md5: 文件MD5值
            parent_id: 父文件夹ID
        
        Returns:
            Dict[str, Any]: 秒传成功返回文件信息，失败返回None
        """
        try:
            # 第一步：创建上传文件请求，检查文件是否已存在（参考Go版本的OldUploadCreate）
            url = f"{API_URL}/createUploadFile.action"
            
            form_data = {
                'parentFolderId': parent_id,
                'fileName': filename,
                'size': str(file_size),
                'md5': file_md5,
                'opertype': '3',  # 参考Go版本
                'flag': '1',      # 参考Go版本
                'resumePolicy': '1',  # 参考Go版本
                'isLog': '0'      # 参考Go版本
            }
            
            headers = self.signature_header(url, "POST")
            
            response = self.session.post(url, data=form_data, headers=headers)
            
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    # 检查fileDataExists字段，1表示文件已存在可以秒传
                    file_data_exists = result.get('fileDataExists', 0)
                    
                    if file_data_exists == 1:
                        # 文件已存在，可以进行秒传
                        upload_file_id = result.get('uploadFileId')
                        file_commit_url = result.get('fileCommitUrl')
                        
                        if upload_file_id and file_commit_url:
                            # 第二步：提交上传确认（参考Go版本的OldUploadCommit）
                            return self._commit_rapid_upload(file_commit_url, upload_file_id, filename)
                        else:
                            self.logger.warning("秒传响应缺少必要字段")
                    else:
                        self.logger.debug(f"文件不存在于云端，无法秒传 (fileDataExists: {file_data_exists})")
                else:
                    error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                    self.logger.debug(f"创建上传文件请求失败: {error_msg}")
            else:
                self.logger.warning(f"创建上传文件请求HTTP错误: {response.status_code}")
                
        except Exception as e:
            self.logger.error(f"秒传请求异常: {e}")
        
        return None
    
    def _commit_rapid_upload(self, file_commit_url: str, upload_file_id: int, filename: str) -> Optional[Dict[str, Any]]:
        """
        提交秒传确认 - 参考Go语言版本的OldUploadCommit实现
        
        Args:
            file_commit_url: 提交URL
            upload_file_id: 上传文件ID
            filename: 文件名
            
        Returns:
            Dict[str, Any]: 提交成功返回文件信息，失败返回None
        """
        try:
            form_data = {
                'opertype': '1',  # 参考Go版本，不覆盖时使用'1'
                'resumePolicy': '1',  # 参考Go版本
                'uploadFileId': str(upload_file_id),
                'isLog': '0'  # 参考Go版本
            }
            
            # 注意：file_commit_url已经是完整的URL，不需要添加API_URL前缀
            headers = self.signature_header(file_commit_url, "POST")
            
            response = self.session.post(file_commit_url, data=form_data, headers=headers)
            
            if response.status_code == 200:
                # 根据Go版本，这里可能返回XML格式的响应
                content_type = response.headers.get('content-type', '').lower()
                
                if 'xml' in content_type:
                    # 处理XML响应（参考Go版本的OldCommitUploadFileResp）
                    import xml.etree.ElementTree as ET
                    try:
                        root = ET.fromstring(response.text)
                        file_info = {
                            'id': root.find('id').text if root.find('id') is not None else None,
                            'name': root.find('name').text if root.find('name') is not None else filename,
                            'size': int(root.find('size').text) if root.find('size') is not None else 0,
                            'md5': root.find('md5').text if root.find('md5') is not None else '',
                            'createDate': root.find('createDate').text if root.find('createDate') is not None else ''
                        }
                        
                        if file_info['id']:
                            self.logger.info(f"秒传提交成功: {filename}")
                            return file_info
                        else:
                            self.logger.error("XML响应中缺少文件ID")
                            
                    except ET.ParseError as e:
                        self.logger.error(f"解析XML响应失败: {e}")
                else:
                    # 处理JSON响应
                    try:
                        result = response.json()
                        if result.get('res_code') == 0 or result.get('resCode') == 0:
                            self.logger.info(f"秒传提交成功: {filename}")
                            return result
                        else:
                            error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                            self.logger.error(f"秒传提交失败: {error_msg}")
                    except ValueError as e:
                        self.logger.error(f"解析JSON响应失败: {e}")
            else:
                self.logger.error(f"秒传提交HTTP错误: {response.status_code}")
                
        except Exception as e:
            self.logger.error(f"秒传提交异常: {e}")
        
        return None

    def _upload_file_stream(self, file_data: Union[str, bytes, BinaryIO], filename: str, 
                           file_size: int, file_md5: str, parent_id: str = None, 
                           overwrite: bool = True) -> Optional[Dict[str, Any]]:
        """普通上传文件流
        
        Args:
            file_data: 文件数据
            filename: 文件名
            file_size: 文件大小
            file_md5: 文件MD5
            parent_id: 父文件夹ID
            overwrite: 是否覆盖
        
        Returns:
            Dict[str, Any]: 上传结果
        """
        if parent_id is None:
            parent_id = "-11"  # 根目录
        
        self.logger.info(f"开始上传文件流: {filename}, 大小: {file_size}, MD5: {file_md5}")
        
        # 初始化上传
        upload_info = self._init_upload(filename, file_size, file_md5, parent_id)
        if not upload_info:
            self.logger.error("初始化上传失败")
            return None
        
        self.logger.info(f"初始化上传成功: {upload_info}")
        
        upload_file_id = upload_info.get('uploadFileId')
        file_upload_url = upload_info.get('fileUploadUrl')
        
        if not upload_file_id or not file_upload_url:
            self.logger.error("获取上传信息失败")
            return None
        
        # 直接上传文件到指定URL
        self.logger.info(f"开始上传文件到: {file_upload_url}")
        
        # 准备文件数据
        if isinstance(file_data, str):
            # 文件路径
            with open(file_data, 'rb') as f:
                file_content = f.read()
        elif isinstance(file_data, bytes):
            file_content = file_data
        else:
            # 文件对象
            file_content = file_data.read()
        
        # 设置请求头
        headers = {
            'ResumePolicy': '1',
            'Expect': '100-continue',
            'Edrive-UploadFileId': str(upload_file_id)
        }
        
        # 生成签名头并合并
        signature_headers = self.signature_header(file_upload_url, 'PUT', '')
        headers.update(signature_headers)
        
        try:
            # 使用PUT方法上传文件
            response = self.session.put(file_upload_url, data=file_content, headers=headers)
            self.logger.info(f"文件上传响应: status_code={response.status_code}")
            
            if response.status_code == 200:
                self.logger.info("文件上传成功，开始提交上传")
                # 提交上传
                result = self._commit_upload(upload_info['fileCommitUrl'], upload_file_id)
                if result:
                    self.logger.info(f"提交上传成功: {result}")
                    # 返回标准格式的结果
                    return {
                        'fileId': result.get('id'),
                        'fileName': result.get('name'),
                        'fileSize': int(result.get('size', 0)) if result.get('size') else 0,
                        'isFolder': False,
                        'createTime': result.get('createDate'),
                        'md5': result.get('md5'),
                        'parentId': parent_id
                    }
                else:
                    self.logger.error("提交上传失败")
            else:
                self.logger.error(f"文件上传失败: {response.status_code}, 响应: {response.text}")
        except Exception as e:
            self.logger.error(f"文件上传请求失败: {e}")
        
        return None

    def _init_upload(self, filename: str, file_size: int, file_md5: str, 
                    parent_id: str) -> Optional[Dict[str, Any]]:
        """初始化上传
        
        Args:
            filename: 文件名
            file_size: 文件大小
            file_md5: 文件MD5
            parent_id: 父文件夹ID
        
        Returns:
            Dict[str, Any]: 初始化结果
        """
        url = "https://api.cloud.189.cn/createUploadFile.action"
        
        form_data = {
            'parentFolderId': parent_id,
            'fileName': filename,
            'size': str(file_size),
            'md5': file_md5,
            'opertype': '3',
            'flag': '1',
            'resumePolicy': '1',
            'isLog': '0'
        }
        
        headers = self.signature_header(url, "POST")
        
        self.logger.info(f"初始化上传请求: URL={url}, form_data={form_data}")
        
        try:
            response = self.session.post(url, data=form_data, headers=headers)
            self.logger.info(f"初始化上传响应: status_code={response.status_code}")
            
            if response.status_code == 200:
                try:
                    result = response.json()
                    if result.get('res_code') == 0:
                        upload_info = {
                            'uploadFileId': result.get('uploadFileId'),
                            'fileUploadUrl': result.get('fileUploadUrl'),
                            'fileCommitUrl': result.get('fileCommitUrl'),
                            'fileDataExists': result.get('fileDataExists', 0)
                        }
                        self.logger.info(f"初始化上传成功: {upload_info}")
                        return upload_info
                    else:
                        self.logger.error(f"初始化上传失败: {result.get('res_message')}")
                except Exception as e:
                    self.logger.error(f"解析JSON响应失败: {e}, 响应: {response.text}")
            else:
                self.logger.error(f"初始化上传HTTP错误: {response.status_code}, 响应: {response.text}")
        except Exception as e:
            self.logger.error(f"初始化上传请求失败: {e}")
        
        return None

    def _commit_upload(self, commit_url: str, upload_file_id: str) -> Optional[Dict[str, Any]]:
        """提交上传
        
        Args:
            commit_url: 提交上传的URL
            upload_file_id: 上传文件ID
        
        Returns:
            Dict[str, Any]: 提交结果
        """
        form_data = {
            'opertype': '1',
            'resumePolicy': '1',
            'uploadFileId': upload_file_id,
            'isLog': '0'
        }
        
        headers = self.signature_header(commit_url, "POST")
        
        self.logger.info(f"提交上传请求: URL={commit_url}, form_data={form_data}")
        
        try:
            response = self.session.post(commit_url, data=form_data, headers=headers)
            self.logger.info(f"提交上传响应: status_code={response.status_code}")
            
            if response.status_code == 200:
                try:
                    response_text = response.text.strip()
                    if response_text.startswith('<?xml'):
                        # 解析XML响应
                        import xml.etree.ElementTree as ET
                        root = ET.fromstring(response_text)
                        
                        file_info = {
                            'id': root.find('id').text if root.find('id') is not None else None,
                            'name': root.find('name').text if root.find('name') is not None else None,
                            'size': root.find('size').text if root.find('size') is not None else None,
                            'md5': root.find('md5').text if root.find('md5') is not None else None,
                            'createDate': root.find('createDate').text if root.find('createDate') is not None else None,
                            'rev': root.find('rev').text if root.find('rev') is not None else None
                        }
                        self.logger.info(f"提交上传成功: {file_info}")
                        return file_info
                    else:
                        # 尝试解析JSON响应
                        result = response.json()
                        if result.get('res_code') == 0:
                            file_info = result.get('file', {})
                            self.logger.info(f"提交上传成功: {file_info}")
                            return file_info
                        else:
                            self.logger.error(f"提交上传失败: {result.get('res_message')}")
                except Exception as e:
                    self.logger.error(f"解析响应失败: {e}, 响应: {response.text}")
            else:
                self.logger.error(f"提交上传HTTP错误: {response.status_code}, 响应: {response.text}")
        except Exception as e:
            self.logger.error(f"提交上传请求失败: {e}")
        
        return None

    def get_file_info(self, remote_path: str) -> Optional[Dict[str, Any]]:
        """
        获取文件信息 - 支持天翼云盘的正常层级结构
        
        Args:
            remote_path: 远程文件路径
            
        Returns:
            Optional[Dict[str, Any]]: 文件信息，不存在返回None
        """
        if not self.is_login():
            self.logger.error("未登录，无法获取文件信息")
            return None
        
        # 标准化路径
        normalized_path = self._normalize_path(remote_path)
        
        # 空路径或根目录，返回根目录信息
        if not normalized_path:
            return {
                'id': '-11',
                'name': '/',
                'size': 0,
                'isFolder': True,
                'createTime': '',
                'md5': '',
                'parentId': ''
            }
        
        # 尝试从路径缓存获取
        cached_info = self.path_cache.get(normalized_path)
        if cached_info is not None:
            self.logger.debug(f"从路径缓存获取文件信息: {normalized_path}")
            return cached_info
        
        try:
            # 提取父路径和文件/文件夹名
            parent_path, item_name = self._extract_parent_path_and_name(normalized_path)
            
            # 获取父目录ID
            if not parent_path:
                parent_id = "-11"  # 根目录
            else:
                parent_id = self._find_folder_id_by_path_cached(parent_path)
                if not parent_id:
                    self.logger.debug(f"父路径不存在: {parent_path}")
                    return None
            
            self.logger.debug(f"在父目录查找文件: 父路径={parent_path}, 父ID={parent_id}, 查找名称={item_name}")
            
            # 在父目录中查找文件/文件夹
            files = self.get_files(parent_id)
            if files:
                self.logger.debug(f"父目录中找到 {len(files)} 个文件")
                for file in files:
                    file_name = file.get('name', '')
                    self.logger.debug(f"检查文件: '{file_name}' vs '{item_name}'")
                    
                    # 只比较文件名，不是完整路径
                    if file_name == item_name:
                        self.logger.debug(f"找到匹配文件: {file_name}")
                        # 统一字段名，将API返回的字段名转换为标准字段名
                        file_info = {
                            'id': file.get('id'),
                            'name': file.get('name'),
                            'size': file.get('size'),
                            'isFolder': file.get('isFolder', False),
                            'createTime': file.get('createDate'),
                            'md5': file.get('md5'),
                            'parentId': parent_id
                        }
                        
                        # 将结果放入路径缓存
                        self.path_cache.put(normalized_path, file_info)
                        
                        return file_info
                
                self.logger.debug(f"在父目录中未找到文件: {item_name}")
                # 输出所有文件名用于调试
                all_files = [f.get('name', '') for f in files]
                self.logger.debug(f"父目录中的所有文件: {all_files[:10]}...")  # 只显示前10个避免日志过长
            else:
                self.logger.debug(f"父目录为空或获取失败")
            
            return None
            
        except Exception as e:
            self.logger.error(f"获取文件信息异常: {e}")
            return None

    def _find_folder_id_by_path_cached(self, path: str) -> Optional[str]:
        """
        根据路径查找文件夹ID - 支持真正的层级结构
        
        Args:
            path: 文件夹路径
            
        Returns:
            Optional[str]: 文件夹ID，找不到返回None
        """
        if path == "/" or path == "":
            return "-11"
        
        # 标准化路径
        normalized_path = self._normalize_path(path)
        if not normalized_path:
            return "-11"
        
        # 尝试从路径缓存获取
        cached_info = self.path_cache.get(normalized_path)
        if cached_info is not None and cached_info.get('isFolder'):
            self.logger.debug(f"从路径缓存获取文件夹ID: {normalized_path} -> {cached_info.get('id')}")
            return cached_info.get('id')
        
        # 处理多层路径，逐层查找并缓存
        path_parts = normalized_path.strip('/').split('/')
        current_folder_id = "-11"  # 从根目录开始
        current_path = ""
        
        for part in path_parts:
            current_path = current_path + '/' + part if current_path else '/' + part
            
            # 检查当前路径是否在缓存中
            cached_folder = self.path_cache.get(current_path)
            if cached_folder is not None and cached_folder.get('isFolder'):
                current_folder_id = cached_folder.get('id')
                self.logger.debug(f"从缓存获取中间路径: {current_path} -> {current_folder_id}")
                continue
            
            # 在当前文件夹中查找下一级文件夹（按文件夹名称查找，不是完整路径）
            folder_found = False
            files = self.get_files(current_folder_id)
            if files:
                for file in files:
                    file_name = file.get('name', '')
                    is_folder = file.get('isFolder', False)
                    file_id = file.get('id', '')
                    
                    # 关键修复：只比较文件夹名称，不是完整路径
                    if file_name == part and is_folder:
                        current_folder_id = file_id
                        folder_found = True
                        
                        # 将找到的文件夹信息放入缓存
                        folder_info = {
                            'id': file_id,
                            'name': file_name,  # 只存储文件夹名称
                            'isFolder': True,
                            'parentId': current_folder_id,
                            'path': current_path  # 完整路径作为额外信息
                        }
                        self.path_cache.put(current_path, folder_info)
                        
                        self.logger.debug(f"找到并缓存文件夹: {current_path} -> {file_id} (名称: {file_name})")
                        break
            
            if not folder_found:
                self.logger.debug(f"找不到文件夹路径: {current_path} (查找名称: {part})")
                return None
        
        return current_folder_id
    
    def _find_folder_id_by_path_simple(self, path: str) -> Optional[str]:
        """
        根据路径查找文件夹ID - 简化版本，用于处理单层路径
        
        Args:
            path: 文件夹路径
            
        Returns:
            Optional[str]: 文件夹ID，找不到返回None
        """
        if path == "/" or path == "":
            return "-11"
        
        # 处理路径，去掉前导斜杠
        folder_name = path.strip("/")
        self.logger.info(f"开始查找文件夹: '{folder_name}' (原路径: '{path}')")
        
        # 添加重试机制，因为文件夹创建后可能需要一些时间才能在列表中显示
        import time
        max_retries = 3
        for attempt in range(max_retries):
            try:
                self.logger.info(f"第 {attempt + 1} 次尝试查找文件夹...")
                files = self.get_files("-11")  # 根目录
                if files:
                    self.logger.info(f"根目录共有 {len(files)} 个文件/文件夹")
                    for i, file in enumerate(files):
                        file_name = file.get('name', '')
                        is_folder = file.get('isFolder', False)
                        file_id = file.get('id', '')
                        self.logger.info(f"  [{i+1}] 名称: '{file_name}', 类型: {'文件夹' if is_folder else '文件'}, ID: {file_id}")
                        
                        if file_name == folder_name and is_folder:
                            self.logger.info(f"✓ 找到文件夹 '{folder_name}', ID: {file_id}")
                            return file_id
                    
                    self.logger.warning(f"第 {attempt + 1} 次尝试未找到文件夹: '{folder_name}'")
                    if attempt < max_retries - 1:
                        self.logger.info("等待 2 秒后重试...")
                        time.sleep(2)
                else:
                    self.logger.warning(f"第 {attempt + 1} 次尝试获取根目录文件列表为空")
                    if attempt < max_retries - 1:
                        time.sleep(2)
            except Exception as e:
                self.logger.error(f"第 {attempt + 1} 次查找文件夹ID异常: {e}")
                if attempt < max_retries - 1:
                    time.sleep(2)
        
        self.logger.error(f"经过 {max_retries} 次尝试，仍未找到文件夹: '{folder_name}'")
        return None
    
    def get_cache_stats(self) -> Dict[str, Any]:
        """
        获取缓存统计信息
        
        Returns:
            Dict[str, Any]: 缓存统计信息
        """
        return {
            'path_cache': self.path_cache.get_stats(),
            'folder_cache': self.folder_cache.get_stats()
        }
    
    def clear_cache(self) -> None:
        """清空所有缓存"""
        self.path_cache.clear()
        self.folder_cache.clear()
        self.logger.info("已清空所有缓存")
    
    def invalidate_path_cache(self, path_prefix: str) -> int:
        """
        使指定路径前缀的缓存失效
        
        Args:
            path_prefix: 路径前缀
            
        Returns:
            int: 失效的缓存条目数
        """
        count = self.path_cache.invalidate_prefix(path_prefix)
        self.logger.info(f"使路径前缀 '{path_prefix}' 的 {count} 个缓存条目失效")
        return count

    # def download_file(self, remote_path: str, local_path: str) -> Dict[str, Any]:
    #     """
    #     下载文件
    #     
    #     Args:
    #         remote_path: 远程文件路径
    #         local_path: 本地保存路径
    #         
    #     Returns:
    #         Dict[str, Any]: 下载结果
    #     """
    #     try:
    #         # 获取文件信息
    #         file_info = self.get_file_info(remote_path)
    #         if not file_info:
    #             return {
    #                 'success': False,
    #                 'message': '文件不存在或无法获取文件信息',
    #                 'file_size': 0,
    #                 'download_time': 0
    #             }
    #         
    #         if file_info.get('isFolder', False):
    #             return {
    #                 'success': False,
    #                 'message': '不能下载文件夹',
    #                 'file_size': 0,
    #                 'download_time': 0
    #             }
    #         
    #         # 获取下载链接
    #         download_url = self._get_download_url(file_info['fileId'])
    #         if not download_url:
    #             return {
    #                 'success': False,
    #                 'message': '获取下载链接失败',
    #                 'file_size': 0,
    #                 'download_time': 0
    #             }
    #         
    #         # 确保本地目录存在
    #         os.makedirs(os.path.dirname(local_path), exist_ok=True)
    #         
    #         # 下载文件
    #         import time
    #         start_time = time.time()
    #         
    #         response = self.session.get(download_url, stream=True)
    #         response.raise_for_status()
    #         
    #         file_size = 0
    #         with open(local_path, 'wb') as f:
    #             for chunk in response.iter_content(chunk_size=8192):
    #                 if chunk:
    #                     f.write(chunk)
    #                     file_size += len(chunk)
    #         
    #         download_time = time.time() - start_time
    #         
    #         return {
    #             'success': True,
    #             'message': '下载成功',
    #             'local_path': local_path,
    #             'file_size': file_size,
    #             'download_time': download_time
    #         }
    #         
    #     except Exception as e:
    #         return {
    #             'success': False,
    #             'message': f'下载失败: {str(e)}',
    #             'file_size': 0,
    #             'download_time': 0
    #         }
    
    def get_file_info(self, path: str) -> Optional[Dict[str, Any]]:
        """
        根据路径获取文件信息
        
        Args:
            path: 文件路径
            
        Returns:
            Optional[Dict[str, Any]]: 文件信息，包含id, name, size, isFolder等字段
        """
        try:
            return self.path_resolver.get_file_info_by_path(path)
        except Exception as e:
            self.logger.error(f"获取文件信息失败: {path}, 错误: {e}")
            return None
    
    def get_file_id(self, path: str) -> Optional[str]:
        """
        根据路径获取文件ID
        
        Args:
            path: 文件路径
            
        Returns:
            Optional[str]: 文件ID
        """
        try:
            return self.path_resolver.get_file_id_by_path(path)
        except Exception as e:
            self.logger.error(f"获取文件ID失败: {path}, 错误: {e}")
            return None
    
    def get_folder_id(self, path: str) -> Optional[str]:
        """
        根据路径获取文件夹ID
        
        Args:
            path: 文件夹路径
            
        Returns:
            Optional[str]: 文件夹ID
        """
        try:
            return self.path_resolver.get_folder_id_by_path(path)
        except Exception as e:
            self.logger.error(f"获取文件夹ID失败: {path}, 错误: {e}")
            return None
    
    def _get_download_url(self, file_id: str) -> Optional[str]:
        """
        获取文件下载链接 - 严格按照Go实现优化
        
        Args:
            file_id: 文件ID
            
        Returns:
            Optional[str]: 下载链接
        """
        try:
            # 严格按照Go实现的Link方法
            url = "https://api.cloud.189.cn/getFileDownloadUrl.action"
            
            # 使用Go实现相同的参数结构
            # Go: r.SetQueryParam("fileId", file.GetID())
            # Go: r.SetQueryParams(map[string]string{"dt": "3", "flag": "1"})
            params = {
                'fileId': file_id,
                'dt': '3',
                'flag': '1'
            }
            # Go实现会自动添加clientSuffix()参数
            params.update(self.client_suffix())
            
            # 使用Go实现相同的签名方式
            # 对于下载URL获取，没有需要加密的参数，所以params为空字符串
            # 对于个人云，is_family为False
            headers = self.signature_header(url, "GET", "", False)
            
            self.logger.debug(f"获取下载链接请求: fileId={file_id}, params={params}")
            
            # 使用带重试的GET请求，自动处理session刷新
            response = self.request_with_retry("GET", url, params=params, headers=headers, timeout=30)
            
            if response.status_code != 200:
                self.logger.error(f"获取下载链接失败，状态码: {response.status_code}")
                return None
            
            result = response.json()
            self.logger.debug(f"下载链接响应: {result}")
            
            # 检查响应状态
            if result.get('res_code') == 0 or result.get('resCode') == 0:
                download_url = result.get('fileDownloadUrl', '')
                
                if download_url:
                    # 严格按照Go实现处理URL
                    # Go: downloadUrl.URL = strings.Replace(strings.ReplaceAll(downloadUrl.URL, "&amp;", "&"), "http://", "https://", 1)
                    download_url = download_url.replace('&amp;', '&').replace('http://', 'https://', 1)
                    
                    # 处理重定向获取真实链接，参考Go实现
                    try:
                        # Go使用NoRedirectClient，我们使用allow_redirects=False
                        redirect_response = self.session.get(
                            download_url, 
                            allow_redirects=False,
                            timeout=10
                        )
                        
                        if redirect_response.status_code == 302:
                            final_url = redirect_response.headers.get('location', download_url)
                            self.logger.debug(f"重定向到最终下载URL: {final_url}")
                            return final_url
                        else:
                            return download_url
                            
                    except Exception as redirect_error:
                        self.logger.warning(f"处理重定向时出错: {redirect_error}，使用原始URL")
                        return download_url
                else:
                    self.logger.error("响应中未找到下载URL")
                    return None
            else:
                error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                self.logger.error(f"获取下载链接失败: {error_msg}")
                return None
                
        except Exception as e:
            self.logger.error(f"获取下载链接异常: {e}")
            return None

    def delete_file(self, remote_path: str, permanent: bool = False) -> Dict[str, Any]:
        """
        删除文件或文件夹 - 严格按照Go实现
        
        Go实现关键点：
        1. 使用CreateBatchTask创建DELETE任务
        2. BatchTaskInfo包含：fileId, fileName, isFolder
        3. JSON字段名是小写：fileId, fileName, isFolder
        
        Args:
            remote_path: 远程文件路径
            permanent: 是否永久删除（天翼云盘暂不支持此参数，保留用于接口兼容）
            
        Returns:
            Dict[str, Any]: 删除结果
        """
        try:
            # 获取文件信息
            file_info = self.get_file_info(remote_path)
            if not file_info:
                return {
                    'success': False,
                    'message': '文件不存在或无法获取文件信息'
                }
            
            # 关键修复：get_file_info返回的字段是'name'而不是'fileName'
            file_id = file_info['id']
            file_name = file_info['name']  # 修复：使用'name'字段
            is_folder = file_info.get('isFolder', False)
            
            # 创建删除任务
            url = "https://api.cloud.189.cn/batch/createBatchTask.action"
            
            task_info = {
                'fileId': file_id,
                'fileName': file_name,
                'isFolder': 1 if is_folder else 0
            }
            
            params = {
                'type': 'DELETE',
                'taskInfos': json.dumps([task_info])
            }
            params.update(self.client_suffix())
            
            headers = self.signature_header(url, "POST")
            
            response = self.session.post(url, data=params, headers=headers)
            response.raise_for_status()
            
            result = response.json()
            if result.get('res_code') != 0 and result.get('resCode') != 0:
                error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                return {
                    'success': False,
                    'message': f'创建删除任务失败: {error_msg}'
                }
            
            task_id = result.get('taskId')
            if not task_id:
                return {
                    'success': False,
                    'message': '获取任务ID失败'
                }
            
            # 等待删除任务完成
            success = self._wait_batch_task("DELETE", task_id)
            
            if success:
                # 删除成功后，清除回收站
                clear_params = {
                    'type': 'CLEAR_RECYCLE',
                    'taskInfos': json.dumps([task_info])
                }
                clear_params.update(self.client_suffix())
                
                clear_response = self.session.post(url, data=clear_params, headers=headers)
                if clear_response.status_code == 200:
                    clear_result = clear_response.json()
                    if clear_result.get('res_code') == 0 or clear_result.get('resCode') == 0:
                        clear_task_id = clear_result.get('taskId')
                        if clear_task_id:
                            self._wait_batch_task("CLEAR_RECYCLE", clear_task_id)
                
                return {
                    'success': True,
                    'message': f'删除{"文件夹" if is_folder else "文件"}成功: {file_name}'
                }
            else:
                return {
                    'success': False,
                    'message': f'删除{"文件夹" if is_folder else "文件"}失败: {file_name}'
                }
                
        except Exception as e:
            return {
                'success': False,
                'message': f'删除失败: {str(e)}'
            }
    
    def create_batch_task(self, task_type: str, target_folder_id: str = "", task_infos: List[Dict[str, Any]] = None, **kwargs) -> Optional[Dict[str, Any]]:
        """
        创建批量任务 - 参考Go语言版本实现
        
        Args:
            task_type: 任务类型 (COPY, MOVE, DELETE, RENAME等)
            target_folder_id: 目标文件夹ID
            task_infos: 任务信息列表
            **kwargs: 其他参数
            
        Returns:
            Optional[Dict[str, Any]]: 批量任务响应，包含taskId
        """
        if not self.is_login():
            self.logger.error("未登录，无法创建批量任务")
            return None
        
        if task_infos is None:
            task_infos = []
        
        url = f"{API_URL}/batch/createBatchTask.action"
        
        # 构建表单数据
        form_data = {
            'type': task_type,
            'taskInfos': json.dumps(task_infos)
        }
        
        if target_folder_id:
            form_data['targetFolderId'] = target_folder_id
        
        # 添加其他参数
        form_data.update(kwargs)
        
        headers = self.signature_header(url, "POST")
        
        try:
            response = self.session.post(url, data=form_data, headers=headers)
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    self.logger.info(f"批量任务创建成功: {task_type}, 任务ID: {result.get('taskId')}")
                    return result
                else:
                    error_msg = result.get('res_message') or result.get('resMessage', '未知错误')
                    self.logger.error(f"创建批量任务失败: {error_msg}")
            else:
                self.logger.error(f"创建批量任务请求失败，状态码: {response.status_code}")
        except Exception as e:
            self.logger.error(f"创建批量任务异常: {e}")
        
        return None
    
    def check_batch_task(self, task_type: str, task_id: str) -> Optional[Dict[str, Any]]:
        """
        检查批量任务状态
        
        Args:
            task_type: 任务类型
            task_id: 任务ID
            
        Returns:
            Optional[Dict[str, Any]]: 任务状态信息
        """
        if not self.is_login():
            return None
        
        url = f"{API_URL}/batch/checkBatchTask.action"
        
        form_data = {
            'type': task_type,
            'taskId': task_id
        }
        
        headers = self.signature_header(url, "POST")
        
        try:
            response = self.session.post(url, data=form_data, headers=headers)
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    return result
                else:
                    error_msg = result.get('res_message') or result.get('resMessage', '未知错误')
                    self.logger.error(f"检查批量任务状态失败: {error_msg}")
        except Exception as e:
            self.logger.error(f"检查批量任务状态异常: {e}")
        
        return None

    def request_with_retry(self, method: str, url: str, **kwargs) -> requests.Response:
        """
        带重试的请求方法 - 自动处理session刷新
        
        Args:
            method: HTTP方法
            url: 请求URL
            **kwargs: 其他请求参数
            
        Returns:
            requests.Response: 响应对象
        """
        try:
            # 第一次请求
            response = self.session.request(method, url, **kwargs)
            
            # 检查是否需要刷新session
            if response.status_code == 200:
                response_text = response.text
                if 'userSessionBO is null' in response_text or 'InvalidSessionKey' in response_text:
                    self.logger.warning("检测到session过期，尝试刷新...")
                    if self.refresh_session():
                        # 刷新成功，重试请求
                        self.logger.info("session刷新成功，重试请求...")
                        response = self.session.request(method, url, **kwargs)
                    else:
                        self.logger.error("session刷新失败")
            elif response.status_code == 400:
                # 400错误可能是session问题，尝试刷新
                self.logger.warning("收到400错误，尝试刷新session...")
                if self.refresh_session():
                    self.logger.info("session刷新成功，重试请求...")
                    response = self.session.request(method, url, **kwargs)
            
            return response
            
        except Exception as e:
            self.logger.error(f"请求异常: {e}")
            raise

    def check_quick_upload(self, file_path: str, file_md5: str, file_size: int) -> bool:
        """
        检查是否可以秒传 - 实现check_quick_upload方法
        
        Args:
            file_path: 文件路径
            file_md5: 文件MD5值
            file_size: 文件大小
            
        Returns:
            bool: 是否可以秒传
        """
        try:
            self.logger.debug(f"检查秒传: {file_path}, MD5: {file_md5}, 大小: {file_size}")
            
            # 使用现有的秒传逻辑
            url = f"{API_URL}/createFileByFile.action"
            
            form_data = {
                'parentFolderId': self._find_folder_id_by_path_cached(os.path.dirname(file_path)),
                'fileName': os.path.basename(file_path),
                'fileSize': str(file_size),
                'md5': file_md5,
                'lastWrite': str(int(time.time() * 1000)),
                'flag': '1',
                'resumePolicy': '1',
                'isLog': '0'
            }
            
            headers = self.signature_header(url, "POST")
            
            response = self.session.post(url, data=form_data, headers=headers, timeout=30)
            
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    self.logger.info(f"秒传检查成功: {file_path}")
                    return True
                else:
                    error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                    self.logger.debug(f"秒传检查失败: {error_msg}")
                    return False
            else:
                self.logger.debug(f"秒传检查请求失败，状态码: {response.status_code}")
                return False
                
        except Exception as e:
            self.logger.error(f"秒传检查异常: {e}")
            return False

    def refresh_session(self) -> bool:
        """
        刷新会话 - 严格按照Go实现优化
        
        Returns:
            bool: 刷新是否成功
        """
        try:
            self.logger.debug("开始刷新会话...")
            
            # 严格按照Go实现的refreshSession方法
            url = f"{API_URL}/getUserSession.action"
            
            params = {
                'appId': APP_ID,
                'accessToken': self.token_info.get('accessToken', '')
            }
            params.update(self.client_suffix())
            
            headers = self.signature_header(url, "GET", "", False)
            
            response = self.session.get(url, params=params, headers=headers, timeout=30)
            
            if response.status_code == 200:
                result = response.json()
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    # 更新token信息
                    new_token_info = {
                        'accessToken': result.get('accessToken', ''),
                        'sessionKey': result.get('sessionKey', ''),
                        'sessionSecret': result.get('sessionSecret', ''),
                        'familySessionKey': result.get('familySessionKey', ''),
                        'familySessionSecret': result.get('familySessionSecret', ''),
                        'refreshToken': result.get('refreshToken', ''),
                        'loginName': result.get('loginName', ''),
                        'getFileDiffSpan': result.get('getFileDiffSpan', 60),
                        'getUserInfoSpan': result.get('getUserInfoSpan', 600),
                        'isSaveName': result.get('isSaveName', 'true'),
                        'keepAlive': result.get('keepAlive', 1000)
                    }
                    
                    self.token_info.update(new_token_info)
                    
                    # 保存到缓存
                    if hasattr(self, 'persistence_manager') and self.persistence_manager:
                        self.persistence_manager.save_token_info(self.username, self.token_info)
                    
                    self.logger.info("会话刷新成功")
                    return True
                else:
                    error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                    self.logger.error(f"刷新会话失败: {error_msg}")
                    return False
            else:
                self.logger.error(f"刷新会话请求失败，状态码: {response.status_code}")
                return False
                
        except Exception as e:
            self.logger.error(f"刷新会话异常: {e}")
            return False

    def _wait_batch_task(self, task_type: str, task_id: str, check_interval: float = 0.4, max_wait_time: int = 60) -> bool:
        """
        等待批处理任务完成 - 严格按照Go实现优化
        
        Args:
            task_type: 任务类型
            task_id: 任务ID
            check_interval: 检查间隔（秒），默认0.4秒，参考Go实现
            max_wait_time: 最大等待时间（秒）
        
        Returns:
            bool: 任务是否成功完成
        """
        import time
        
        # 严格按照Go实现的WaitBatchTask方法
        url = "https://api.cloud.189.cn/batch/checkBatchTask.action"
        
        start_time = time.time()
        check_count = 0
        
        self.logger.debug(f"开始等待{task_type}任务完成，任务ID: {task_id}")
        
        while time.time() - start_time < max_wait_time:
            check_count += 1
            
            # 使用Go实现相同的参数
            params = {
                'type': task_type,
                'taskId': task_id
            }
            params.update(self.client_suffix())
            
            headers = self.signature_header(url, "POST")
            
            try:
                # 使用POST请求，参考Go实现的post方法
                response = self.session.post(url, data=params, headers=headers, timeout=10)
                
                if response.status_code == 200:
                    result = response.json()
                    if result.get('res_code') == 0 or result.get('resCode') == 0:
                        task_status = result.get('taskStatus')
                        self.logger.debug(f"任务状态检查 #{check_count}: {task_status}")
                        
                        # 严格按照Go实现的逻辑
                        if task_status == 4:  # 任务完成
                            self.logger.debug(f"{task_type}任务完成")
                            return True
                        elif task_status == 2:  # 存在冲突
                            # Go实现直接返回ErrIsConflict，但我们之前发现有些情况下状态2但消息是"成功"
                            error_msg = result.get('res_message', result.get('resMessage', '存在冲突'))
                            if error_msg == "成功":
                                self.logger.debug(f"{task_type}任务完成（状态2但消息为成功）")
                                return True
                            else:
                                self.logger.error(f"{task_type}任务冲突: {error_msg}")
                                return False
                        elif task_status in [1, 3]:  # 任务初始化或执行中
                            # 继续等待
                            if check_count % 10 == 0:  # 每10次检查输出一次进度
                                elapsed = time.time() - start_time
                                self.logger.debug(f"{task_type}任务执行中... 已等待 {elapsed:.1f}秒")
                        else:
                            # 未知状态
                            error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                            self.logger.error(f"{task_type}任务未知状态 {task_status}: {error_msg}")
                            return False
                    else:
                        error_msg = result.get('res_message', result.get('resMessage', '未知错误'))
                        self.logger.error(f"检查任务状态失败: {error_msg}")
                        return False
                else:
                    self.logger.error(f"检查任务状态请求失败，状态码: {response.status_code}")
                    return False
                    
            except Exception as e:
                self.logger.error(f"检查任务状态异常: {e}")
                return False
            
            # 使用Go实现相同的等待时间：time.Millisecond*400 = 0.4秒
            time.sleep(check_interval)
        
        self.logger.error(f"{task_type}任务超时，等待时间: {max_wait_time}秒")
        return False

    # ==============================
    # BaseCloudClient 接口实现
    # ==============================
    
    # 为了避免方法名冲突，为BaseCloudClient接口添加适配器方法
    
    def login(self, credentials: LoginCredentials) -> PersistentLoginInfo:
        """
        使用凭据登录 - BaseCloudClient接口实现
        
        Args:
            credentials: 登录凭据
            
        Returns:
            PersistentLoginInfo: 持久化登录信息
        """
        return self.login_with_credentials(credentials)

    def login_with_credentials(self, credentials: LoginCredentials) -> PersistentLoginInfo:
        """
        使用凭据登录 - BaseCloudClient接口实现
        
        Args:
            credentials: 登录凭据
            
        Returns:
            PersistentLoginInfo: 持久化登录信息
        """
        # 处理缓存token的情况
        if credentials.extra_params and 'cache_token' in credentials.extra_params:
            cache_token = credentials.extra_params['cache_token']
            
            # 如果cache_token是字典，直接使用
            if isinstance(cache_token, dict):
                self.token_info = cache_token.get('token_info')
                self.identity = cache_token.get('identity')
                if credentials.username:
                    self.username = credentials.username
                
                # 验证登录状态
                if self.is_login():
                    self.is_authenticated = True  # 设置认证状态
                    return PersistentLoginInfo(
                        provider="tianyi_pc",
                        token=self.token_info.get('accessToken') if self.token_info else None,
                        extra_data=self.token_info
                    )
        
        # 设置用户名和密码
        if credentials.username:
            self.username = credentials.username
        if credentials.password:
            self.password = credentials.password
            
        # 调用原始登录方法
        success = self.login_internal()  # 调用重命名后的login_internal方法
        
        if success and self.token_info:
            self.is_authenticated = True  # 设置认证状态
            # 构造持久化登录信息
            return PersistentLoginInfo(
                provider="tianyi_pc",
                token=self.token_info.get('accessToken'),
                expires_at=datetime.fromtimestamp(self.token_info.get('expireTime', 0) / 1000) if self.token_info.get('expireTime') else None,
                extra_data=self.token_info
            )
        else:
            raise Exception("登录失败")
    
    def login_with_persistent_info(self, persistent_info: PersistentLoginInfo) -> bool:
        """
        使用持久化信息登录 - BaseCloudClient接口实现
        
        Args:
            persistent_info: 持久化登录信息
            
        Returns:
            bool: 登录是否成功
        """
        if persistent_info.extra_data:
            self.token_info = persistent_info.extra_data
            self.identity = persistent_info.extra_data.get('identity')
            if self.is_login():
                self.is_authenticated = True  # 设置认证状态
                return True
        return False
    
    def refresh_login(self) -> Optional[PersistentLoginInfo]:
        """
        刷新登录状态 - BaseCloudClient接口实现
        
        Returns:
            Optional[PersistentLoginInfo]: 刷新后的持久化登录信息
        """
        if self.check_login_status():
            if self.token_info:
                return PersistentLoginInfo(
                    provider="tianyi",
                    token=self.token_info.get('accessToken'),
                    expires_at=datetime.fromtimestamp(self.token_info.get('expireTime', 0) / 1000) if self.token_info.get('expireTime') else None,
                    extra_data=self.token_info
                )
        return None
    
    def logout_client(self) -> bool:
        """
        登出 - BaseCloudClient接口实现（代理原方法）
        
        Returns:
            bool: 登出是否成功
        """
        return self.logout()  # 调用原始的logout方法
    
    def is_login_valid(self) -> bool:
        """
        检查登录是否有效 - BaseCloudClient接口实现（代理原方法）
        
        Returns:
            bool: 登录是否有效
        """
        return self.is_login()  # 调用原始的is_login方法
    
    def upload_file(self, file_stream: Union[bytes, BinaryIO], remote_path: str, **kwargs) -> bool:
        """
        上传文件流 - 支持天翼云盘的正常层级结构
        
        Args:
            file_stream: 文件流或字节数据
            remote_path: 远程路径
            **kwargs: 其他参数
            
        Returns:
            bool: 上传是否成功
        """
        # 标准化路径
        normalized_path = self._normalize_path(remote_path)
        
        if not normalized_path:
            self.logger.error("无效的文件路径")
            return False
        
        # 提取父路径和文件名
        parent_path, filename = self._extract_parent_path_and_name(normalized_path)
        
        self.logger.debug(f"上传文件: 完整路径={normalized_path}, 父路径={parent_path}, 文件名={filename}")
        
        # 获取父目录ID
        if not parent_path:
            # 文件在根目录
            parent_id = "-11"
        else:
            # 确保父路径存在
            parent_id = self._find_folder_id_by_path_cached(parent_path)
            if not parent_id:
                self.logger.debug(f"父路径不存在，创建文件夹: {parent_path}")
                if not self.create_folder_standard(parent_path):
                    self.logger.error(f"创建父路径失败: {parent_path}")
                    return False
                # 重新获取父目录ID
                parent_id = self._find_folder_id_by_path_cached(parent_path)
                if not parent_id:
                    self.logger.error(f"创建父路径后仍无法获取ID: {parent_path}")
                    return False
        
        # 调用原始上传方法（只传递文件名，不是完整路径）
        result = self.upload_file_internal(
            file_data=file_stream,
            filename=filename,  # 只传递文件名
            parent_id=parent_id,  # 使用正确的父目录ID
            overwrite=kwargs.get('overwrite', True),
            try_fast_upload=kwargs.get('try_fast_upload', True)
        )
        
        # 如果上传成功，将文件信息加入路径缓存
        if result:
            # 获取实际的文件名（可能被天翼网盘修改）
            actual_filename = result.get('name', filename)
            
            file_info = {
                'id': result.get('fileId'),
                'name': actual_filename,  # 只存储文件名
                'size': result.get('fileSize'),
                'isFolder': False,
                'createTime': result.get('createTime'),
                'md5': result.get('md5'),
                'parentId': parent_id
            }
            # 将结果放入路径缓存，使用完整路径作为key
            self.path_cache.put(normalized_path, file_info)
            self.logger.debug(f"已将上传文件信息加入缓存: {normalized_path} (文件名: {actual_filename}, 父ID: {parent_id})")
            return True
        
        return False
    
    def download_file_stream(self, remote_path: str) -> BinaryIO:
        """
        下载文件流 - BaseCloudClient接口实现
        
        Args:
            remote_path: 远程文件路径
            
        Returns:
            BinaryIO: 文件流
        """
        # 获取文件信息
        file_info_data = self.get_file_info(remote_path)
        if not file_info_data:
            raise FileNotFoundError(f"文件不存在: {remote_path}")
        
        # 获取下载URL
        file_id = file_info_data.get('id')
        download_url = self._get_download_url(file_id)
        if not download_url:
            raise Exception(f"无法获取下载链接: {remote_path}")
        
        # 下载文件流
        response = self.session.get(download_url, stream=True)
        response.raise_for_status()
        
        return io.BytesIO(response.content)
    
    def get_download_url(self, remote_path: str, expires_in: int = 3600) -> str:
        """
        获取下载链接 - BaseCloudClient接口实现
        
        Args:
            remote_path: 远程文件路径
            expires_in: 过期时间（秒）
            
        Returns:
            str: 下载链接
        """
        # 获取文件信息
        file_info_data = self.get_file_info(remote_path)
        if not file_info_data:
            raise FileNotFoundError(f"文件不存在: {remote_path}")
        
        # 获取下载URL
        file_id = file_info_data.get('id')
        download_url = self._get_download_url(file_id)
        if not download_url:
            raise Exception(f"无法获取下载链接: {remote_path}")
        
        return download_url
    
    def list_files(self, remote_path: str = "/") -> List[FileInfo]:
        """
        列出目录下的文件 - BaseCloudClient接口实现（适配器方法）
        
        Args:
            remote_path: 远程目录路径
            
        Returns:
            List[FileInfo]: 文件信息列表
        """
        # 根据路径获取folder_id（这里简化处理）
        folder_id = "-11"  # 默认根目录
        if remote_path != "/" and remote_path != "":
            # 实际实现中需要路径解析逻辑
            pass
        
        # 调用原始的get_files方法
        files_data = self.get_files(folder_id=folder_id)
        if not files_data:
            return []
        
        # 转换为FileInfo对象
        file_infos = []
        for file_data in files_data:
            # 确保数据类型转换正确
            try:
                size = int(file_data.get('size', 0)) if file_data.get('size') else None
            except (ValueError, TypeError):
                size = None
                
            try:
                create_time = int(file_data.get('createTime', 0)) if file_data.get('createTime') else None
                created_at = datetime.fromtimestamp(create_time / 1000) if create_time else None
            except (ValueError, TypeError):
                created_at = None
                
            try:
                last_op_time = int(file_data.get('lastOpTime', 0)) if file_data.get('lastOpTime') else None
                updated_at = datetime.fromtimestamp(last_op_time / 1000) if last_op_time else None
            except (ValueError, TypeError):
                updated_at = None
            
            file_info = FileInfo(
                name=file_data.get('name', ''),
                path=os.path.join(remote_path, file_data.get('name', '')),
                is_dir=file_data.get('isFolder', False),
                size=size,
                md5=file_data.get('md5'),
                created_at=created_at,
                updated_at=updated_at,
                extra_info=file_data
            )
            file_infos.append(file_info)
        
        return file_infos
    
    def get_file_info_standard(self, remote_path: str) -> FileInfo:
        """
        获取文件信息 - BaseCloudClient接口实现（适配器方法）
        
        Args:
            remote_path: 远程文件路径
            
        Returns:
            FileInfo: 文件信息
        """
        # 调用原始的get_file_info方法
        file_data = self.get_file_info(remote_path)
        if not file_data:
            raise FileNotFoundError(f"文件不存在: {remote_path}")
        
        # 转换为FileInfo对象
        return FileInfo(
            name=file_data.get('name', ''),
            path=remote_path,
            is_dir=file_data.get('isFolder', False),
            size=file_data.get('size'),
            md5=file_data.get('md5'),
            created_at=datetime.fromtimestamp(file_data.get('createTime', 0) / 1000) if file_data.get('createTime') else None,
            updated_at=datetime.fromtimestamp(file_data.get('lastOpTime', 0) / 1000) if file_data.get('lastOpTime') else None,
            extra_info=file_data
        )
    
    def create_folder_standard(self, remote_path: str) -> bool:
        """
        创建文件夹 - 支持天翼云盘的正常层级结构
        
        Args:
            remote_path: 远程文件夹路径
            
        Returns:
            bool: 创建是否成功
        """
        # 标准化路径
        normalized_path = self._normalize_path(remote_path)
        
        if not normalized_path:
            self.logger.error("无效的文件夹路径")
            return False
        
        # 检查文件夹是否已存在
        existing_folder_id = self._find_folder_id_by_path_cached(normalized_path)
        if existing_folder_id:
            self.logger.debug(f"文件夹已存在: {normalized_path} (ID: {existing_folder_id})")
            return True
        
        # 提取父路径和文件夹名
        parent_path, folder_name = self._extract_parent_path_and_name(normalized_path)
        
        self.logger.debug(f"创建文件夹: 完整路径={normalized_path}, 父路径={parent_path}, 文件夹名={folder_name}")
        
        # 获取父目录ID
        if not parent_path:
            # 单层路径，直接在根目录创建
            parent_id = "-11"
        else:
            # 多层路径，需要先确保父路径存在
            parent_id = self._find_folder_id_by_path_cached(parent_path)
            if not parent_id:
                self.logger.debug(f"父路径不存在，递归创建: {parent_path}")
                if not self.create_folder_standard(parent_path):
                    self.logger.error(f"创建父路径失败: {parent_path}")
                    return False
                # 重新获取父目录ID
                parent_id = self._find_folder_id_by_path_cached(parent_path)
                if not parent_id:
                    self.logger.error(f"创建父路径后仍无法获取ID: {parent_path}")
                    return False
        
        # 创建文件夹（只传递文件夹名称，不是完整路径）
        result = self.create_folder_internal(folder_name=folder_name, parent_id=parent_id)
        if result:
            # 更新缓存
            folder_info = {
                'id': result.get('fileId'),
                'name': folder_name,  # 只存储文件夹名称
                'size': 0,
                'isFolder': True,
                'createTime': result.get('createTime'),
                'md5': '',
                'parentId': parent_id
            }
            self.path_cache.put(normalized_path, folder_info)
            self.logger.debug(f"成功创建文件夹: {normalized_path} (名称: {folder_name}, 父ID: {parent_id})")
            return True
        
        self.logger.error(f"创建文件夹失败: {normalized_path}")
        return False
    
    def delete_file_standard(self, remote_path: str, permanent: bool = False) -> bool:
        """
        删除文件或文件夹 - BaseCloudClient接口实现（代理原方法）
        
        Args:
            remote_path: 远程文件路径
            permanent: 是否永久删除
            
        Returns:
            bool: 删除是否成功
        """
        # 调用原始的delete_file方法
        result = self.delete_file(remote_path)
        return result.get('success', False) if isinstance(result, dict) else False
    
    def move_file(self, src_path: str, dst_path: str) -> bool:
        """
        移动文件或文件夹 - 优化版本
        
        Args:
            src_path: 源路径
            dst_path: 目标路径
            
        Returns:
            bool: 移动是否成功
        """
        try:
            # 参数验证
            if not src_path or not dst_path:
                self.logger.error("源路径和目标路径不能为空")
                return False
            
            if src_path == dst_path:
                self.logger.warning("源路径和目标路径相同，无需移动")
                return True
            
            # 标准化路径
            src_path = self._normalize_path(src_path)
            dst_path = self._normalize_path(dst_path)
            
            # 获取源文件信息
            src_file_info = self.get_file_info(src_path)
            if not src_file_info:
                self.logger.error(f"源文件不存在: {src_path}")
                return False
            
            # 检查目标路径是否已存在同名文件
            if self.get_file_info(dst_path):
                self.logger.error(f"目标路径已存在文件: {dst_path}")
                return False
            
            # 获取目标目录ID
            dst_dir_path = os.path.dirname(dst_path) if dst_path != "/" else "/"
            dst_folder_id = self._find_folder_id_by_path_cached(dst_dir_path)
            if not dst_folder_id:
                self.logger.error(f"目标目录不存在: {dst_dir_path}")
                return False
            
            # 严格按照Go实现的Move方法构建任务信息
            # Go: BatchTaskInfo{FileId: srcObj.GetID(), FileName: srcObj.GetName(), IsFolder: BoolToNumber(srcObj.IsDir())}
            task_info = {
                'fileId': src_file_info['id'],
                'fileName': src_file_info.get('name', ''),
                'isFolder': 1 if src_file_info.get('isFolder', False) else 0
            }
            
            # Go: other := map[string]string{"targetFileName": dstDir.GetName()}
            other_params = {
                'targetFileName': os.path.basename(dst_path)
            }
            
            self.logger.debug(f"创建移动任务: {task_info}, other_params: {other_params}")
            
            # 使用Go实现相同的参数创建移动任务
            result = self.create_batch_task("MOVE", dst_folder_id, [task_info], **other_params)
            
            if not result:
                self.logger.error("创建移动任务失败")
                return False
            
            task_id = result.get('taskId')
            if not task_id:
                self.logger.error("未获取到任务ID")
                return False
            
            self.logger.debug(f"移动任务ID: {task_id}")
            
            # 等待任务完成
            # 增加超时时间到120秒，因为天翼云API处理时间较长
            success = self._wait_batch_task('MOVE', task_id, 0.4, 120)
            if success:
                self.logger.info(f"文件移动成功: {src_path} -> {dst_path}")
                # 清理相关缓存
                src_dir_path = os.path.dirname(src_path)
                self._invalidate_path_cache(src_dir_path)
                self._invalidate_path_cache(dst_dir_path)
                # 清理文件夹缓存
                src_folder_id = self._find_folder_id_by_path_cached(src_dir_path)
                if src_folder_id:
                    self.folder_cache.remove(src_folder_id)
                self.folder_cache.remove(dst_folder_id)
            else:
                self.logger.error(f"文件移动失败: {src_path} -> {dst_path}")
            
            return success
            
        except Exception as e:
            self.logger.error(f"移动文件异常: {e}")
            return False
    
    def copy_file(self, src_path: str, dst_path: str) -> bool:
        """
        复制文件或文件夹 - 优化版本
        
        Args:
            src_path: 源路径
            dst_path: 目标路径
            
        Returns:
            bool: 复制是否成功
        """
        try:
            # 参数验证
            if not src_path or not dst_path:
                self.logger.error("源路径和目标路径不能为空")
                return False
            
            if src_path == dst_path:
                self.logger.warning("源路径和目标路径相同，无需复制")
                return True
            
            # 标准化路径
            src_path = self._normalize_path(src_path)
            dst_path = self._normalize_path(dst_path)
            
            # 获取源文件信息
            src_file_info = self.get_file_info(src_path)
            if not src_file_info:
                self.logger.error(f"源文件不存在: {src_path}")
                return False
            
            # 检查目标路径是否已存在同名文件
            if self.get_file_info(dst_path):
                self.logger.error(f"目标路径已存在文件: {dst_path}")
                return False
            
            # 获取目标目录ID
            dst_dir_path = os.path.dirname(dst_path) if dst_path != "/" else "/"
            dst_folder_id = self._find_folder_id_by_path_cached(dst_dir_path)
            if not dst_folder_id:
                self.logger.error(f"目标目录不存在: {dst_dir_path}")
                return False
            
            # 严格按照Go实现的Copy方法构建任务信息
            # Go: BatchTaskInfo{FileId: srcObj.GetID(), FileName: srcObj.GetName(), IsFolder: BoolToNumber(srcObj.IsDir())}
            task_info = {
                'fileId': src_file_info['id'],
                'fileName': src_file_info.get('name', ''),
                'isFolder': 1 if src_file_info.get('isFolder', False) else 0
            }
            
            # Go: other := map[string]string{"targetFileName": dstDir.GetName()}
            other_params = {
                'targetFileName': os.path.basename(dst_path)
            }
            
            self.logger.debug(f"创建复制任务: {task_info}, other_params: {other_params}")
            
            # 使用Go实现相同的参数创建复制任务
            result = self.create_batch_task("COPY", dst_folder_id, [task_info], **other_params)
            
            if not result:
                self.logger.error("创建复制任务失败")
                return False
            
            task_id = result.get('taskId')
            if not task_id:
                self.logger.error("未获取到任务ID")
                return False
            
            self.logger.debug(f"复制任务ID: {task_id}")
            
            # 等待任务完成，使用Go实现相同的等待时间：time.Second = 1.0秒
            success = self._wait_batch_task('COPY', task_id, 1.0, 60)
            if success:
                self.logger.info(f"文件复制成功: {src_path} -> {dst_path}")
                # 清理相关缓存
                self._invalidate_path_cache(dst_dir_path)
                self.folder_cache.remove(dst_folder_id)
            else:
                self.logger.error(f"文件复制失败: {src_path} -> {dst_path}")
            
            return success
            
        except Exception as e:
            self.logger.error(f"复制文件异常: {e}")
            return False
    
    def rename_file(self, remote_path: str, new_name: str) -> bool:
        """
        重命名文件或文件夹 - 严格按照Go实现优化
        
        Go实现关键点：
        1. queryParams通过SetQueryParams设置（不加密）
        2. params参数传递nil，所以签名使用空字符串
        3. 签名：SignatureHeader(url, method, "", isFamily)
        
        Args:
            remote_path: 远程文件路径
            new_name: 新名称
            
        Returns:
            bool: 重命名是否成功
        """
        try:
            # 获取文件信息
            file_info = self.get_file_info(remote_path)
            if not file_info:
                self.logger.error(f"文件不存在: {remote_path}")
                return False
            
            file_id = file_info['id']
            is_folder = file_info.get('isFolder', False)
            
            # 严格按照Go实现的Rename方法
            # Go: req.SetContext(ctx).SetQueryParams(queryParam)
            # Go: y.request(fullUrl, method, callback, nil, newObj, isFamily)
            #     其中第4个参数nil表示params为空，签名使用空字符串
            
            query_params = {}
            url = "https://api.cloud.189.cn"
            method = "POST"
            
            if is_folder:
                url += "/renameFolder.action"
                query_params.update({
                    'folderId': file_id,
                    'destFolderName': new_name
                })
            else:
                url += "/renameFile.action"
                query_params.update({
                    'fileId': file_id,
                    'destFileName': new_name
                })
            
            # 添加客户端后缀参数到query_params
            query_params.update(self.client_suffix())
            
            # 关键修复：Go代码中params传递nil，所以签名使用空字符串
            # 签名：SignatureHeader(url, method, paramsData, isFamily)
            # 其中paramsData = EncryptParams(nil) = ""
            headers = self.signature_header(url, method, "")
            
            self.logger.debug(f"重命名请求: {method} {url}, query_params={query_params}")
            self.logger.debug(f"重命名签名使用空字符串（Go params=nil）")
            
            # 使用POST请求，参数作为查询参数（严格按照Go实现）
            response = self.session.post(url, params=query_params, headers=headers, timeout=30)
            
            self.logger.debug(f"重命名响应状态码: {response.status_code}")
            
            if response.status_code == 200:
                result = response.json()
                self.logger.debug(f"重命名响应内容: {result}")
                
                if result.get('res_code') == 0 or result.get('resCode') == 0:
                    self.logger.info(f"文件重命名成功: {remote_path} -> {new_name}")
                    # 清理相关缓存
                    dir_path = os.path.dirname(remote_path)
                    self._invalidate_path_cache(dir_path)
                    folder_id = self._find_folder_id_by_path_cached(dir_path)
                    if folder_id:
                        self.folder_cache.remove(folder_id)
                    return True
                else:
                    error_msg = result.get('res_message') or result.get('resMessage', '未知错误')
                    self.logger.error(f"重命名失败: {error_msg}")
            else:
                self.logger.error(f"重命名请求失败，状态码: {response.status_code}, 响应: {response.text}")
            
            return False
            
        except Exception as e:
            self.logger.error(f"重命名文件异常: {e}", exc_info=True)
            return False
    
    def get_cached_token(self) -> Optional[Dict[str, Any]]:
        """
        获取当前缓存的token信息
        
        Returns:
            Optional[Dict[str, Any]]: 当前的token信息，如果未登录则返回None
        """
        return self.token_info.copy() if self.token_info else None
    
    def file_exists(self, remote_path: str) -> bool:
        """
        检查文件是否存在 - BaseCloudClient接口实现
        
        Args:
            remote_path: 远程文件路径
            
        Returns:
            bool: 文件是否存在
        """
        try:
            file_info_data = self.get_file_info(remote_path)
            return file_info_data is not None
        except:
            return False
    
    def get_account_info(self) -> Optional[AccountInfo]:
        """
        获取账号信息 - BaseCloudClient接口实现
        
        Returns:
            Optional[AccountInfo]: 账号信息
        """
        user_info = self.get_user_info()
        if user_info:
            # 确保数据类型转换正确，API可能返回字符串类型的数值
            try:
                total_space = int(user_info.get('quota', 0))
                used_space = int(user_info.get('usedQuota', 0))
                available_space = total_space - used_space
            except (ValueError, TypeError):
                # 如果转换失败，使用默认值
                total_space = 0
                used_space = 0
                available_space = 0
                
            return AccountInfo(
                username=user_info.get('loginName', ''),
                total_space=total_space,
                used_space=used_space,
                available_space=available_space,
                extra_info=user_info
            )
        return None
    
    def quick_upload(self, file_md5: str, remote_path: str, **kwargs) -> bool:
        """
        秒传文件
        
        Args:
            file_md5: 文件MD5值
            remote_path: 远程路径
            **kwargs: 其他参数，包括file_size等
        
        Returns:
            bool: 秒传是否成功
        """
        try:
            # 解析路径
            path_parts = remote_path.strip('/').split('/')
            filename = path_parts[-1]
            
            # 获取父目录ID
            if len(path_parts) > 1:
                parent_path = '/'.join(path_parts[:-1])
                parent_id = self._find_folder_id_by_path_cached('/' + parent_path)
            else:
                parent_id = '-11'  # 根目录
            
            if not parent_id:
                self.logger.error(f"无法找到父目录: {remote_path}")
                return False
            
            # 获取文件大小
            file_size = kwargs.get('file_size', 0)
            if file_size <= 0:
                self.logger.error("文件大小无效")
                return False
            
            # 尝试秒传
            result = self._fast_upload(filename, file_size, file_md5, parent_id)
            return result is not None
            
        except Exception as e:
            self.logger.error(f"秒传失败: {e}")
            return False